function long2str(v) {
    var vl = v.length;
    var sl = v[vl - 1] & 0xffffffff;
    for (var i = 0; i < vl; i++)
    {
        v[i] = String.fromCharCode(v[i] & 0xff,
                                v[i] >>> 8 & 0xff,
                                v[i] >>> 16 & 0xff,
                                v[i] >>> 24 & 0xff);
    }
    return v.join('');
}

function str2long(s) {
    var len = s.length;
    var v = [];
    for (var i = 0; i < len; i += 4)
    {
        v[i >> 2] = s.charCodeAt(i)
                | s.charCodeAt(i + 1) << 8
                | s.charCodeAt(i + 2) << 16
                | s.charCodeAt(i + 3) << 24;
    }
    return v;
}

key = [1888420705,2576816180, 2347232058, 874813317]

//把key转换为golang的[]byte字节数组
// toUint8Array(key, false)
function toUint8Array(v, includeLength) {
	var n;
	if (includeLength) {
		n = v[v.length - 1];
	} else {
		n = v.length << 2;
	}

	var result = new Uint8Array(n);
	for (var i = 0; i < n; i++) {
		result[i] =  v[i >> 2] >> ((i & 3) << 3);
	}
	return result;
}
	
function xxtea_encrypt(str, key) {
    if (str.length === 0) {
        return '';
    }

    var v = str2long(str);
    var k = key;
    var n = v.length - 1;

    var z = v[n], y = v[0], delta = 0x9E3779B9;

    var mx, e, q = Math.floor(6 + 52 / (n + 1)), sum = 0;
    while (q-- > 0) {
        sum = sum + delta & 0xffffffff;
        e = sum >>> 2 & 3;
        
        for (var p = 0; p < n; p++) {
            y = v[p + 1];
            mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
            
            z = v[p] = v[p] + mx & 0xffffffff;
        }
        y = v[0];
        mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
        z = v[n] = v[n] + mx & 0xffffffff;
    }

    return long2str(v, false);
}

function xxtea_decrypt(str, key) {
    if (str.length = 0) {
        return "";
    }

    var v = str2long(str, false);
    var k = key;
    var n = v.length - 1;

    var z = v[n - 1], y = v[0], delta = 0x9E3779B9;
    var mx, e, q = Math.floor(6 + 52 / (n + 1)), sum = q * delta & 0xffffffff;
    while (sum !== 0) {
        e = sum >>> 2 & 3;
        for (var p = n; p > 0; p--) {
            z = v[p - 1];
            mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
            y = v[p] = v[p] - mx & 0xffffffff;
        }
        z = v[n];
        
        mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
        y = v[0] = v[0] - mx & 0xffffffff;
        sum = sum - delta & 0xffffffff;

    }
   
    return long2str(v, true);
}

// encodeObject(_i1L1)
function encodeObject(str) {
    var value = encodeUTF8(str);
    // var value = encodeUTF8(JSON.stringify(str));
	console.log(crc32(value))
	console.log(encodeHex(crc32(value)))
    var _o0QQo = encodeHex(crc32(value));
    return _o0QQo + "#" + value;
}

function Base64() {

}
Base64._keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
Base64.encode64 = function (input) {
    var output = "";
    var chr1, chr2, chr3 = "";
    var enc1, enc2, enc3, enc4 = "";
    var i = 0;
    do {
        chr1 = input.charCodeAt(i++);
        chr2 = input.charCodeAt(i++);
        chr3 = input.charCodeAt(i++);
        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;
        if (isNaN(chr2)) {
            enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
            enc4 = 64;
        }
        output = output +
           Base64._keyStr.charAt(enc1) +
           Base64._keyStr.charAt(enc2) +
           Base64._keyStr.charAt(enc3) +
           Base64._keyStr.charAt(enc4);
        chr1 = chr2 = chr3 = "";
        enc1 = enc2 = enc3 = enc4 = "";
    } while (i < input.length);
    return output;
}
Base64.decode64 = function (input) {
    var output = "";
    var chr1, chr2, chr3 = "";
    var enc1, enc2, enc3, enc4 = "";
    var i = 0;
    var base64test = /[^A-Za-z0-9\+\/\=\n]/g;
    if (base64test.exec(input)) {
        return "error";
    }
    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
    do {
        enc1 = Base64._keyStr.indexOf(input.charAt(i++));
        enc2 = Base64._keyStr.indexOf(input.charAt(i++));
        enc3 = Base64._keyStr.indexOf(input.charAt(i++));
        enc4 = Base64._keyStr.indexOf(input.charAt(i++));
        chr1 = (enc1 << 2) | (enc2 >> 4);
        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
        chr3 = ((enc3 & 3) << 6) | enc4;
        output = output + String.fromCharCode(chr1);
        if (enc3 != 64) {
            output = output + String.fromCharCode(chr2);
        }
        if (enc4 != 64) {
            output = output + String.fromCharCode(chr3);
        }
        chr1 = chr2 = chr3 = "";
        enc1 = enc2 = enc3 = enc4 = "";
    } while (i < input.length);
    return output;
}

//encodeUTF8(str)
function encodeUTF8(str) {
    var result = [];

    for (var i = 0; i < str.length; i++) {
        var code = str.charCodeAt(i);
        if (code < 128) {
            result.push(String.fromCharCode(code));
        } else if (code >=128 && code < 2048) {
            result.push(String.fromCharCode(code >> 6 | 192));
            result.push(String.fromCharCode(code & 63 |128));
        } else {
            result.push(String.fromCharCode(code >> 12 | 224));
            result.push(String.fromCharCode(code >> 6 & 63 |128));
            result.push(String.fromCharCode(code & 63 |128));
        }
    }

    return result.join('');
}

function decodeUTF8(utftext) {

    var string = "";
    var i = 0;
    var c = c1 = c2 = 0;

    while ( i < utftext.length ) {
        c = utftext.charCodeAt(i);

        if (c < 128) {
            string += String.fromCharCode(c);
            i++;
        } else if((c > 191) && (c < 224)) {
            c2 = utftext.charCodeAt(i+1);
            string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
            i += 2;

        } else {
            c2 = utftext.charCodeAt(i+1);
            c3 = utftext.charCodeAt(i+2);
            string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
            i += 3;
        }
    }
    return string;
}

// encodeHex(str)
// 计算器可以把hex转为dec
// dechex 十进制转换为十六进制, python hex
function encodeHex(str) {
    var chars = "0123456789ABCDEF";

    return [
        chars.charAt(str >>> 28 & 15),
        chars.charAt(str >>> 24 & 15),
        chars.charAt(str >>> 20 & 15),
        chars.charAt(str >>> 16 & 15),
        chars.charAt(str >>> 12 & 15),
        chars.charAt(str >>> 8  & 15),
        chars.charAt(str >>> 4  & 15),
        chars.charAt(str & 15)
    ].join('');
}

// hexdec 十六进制转换为十进制, python int("0xf69b4a79", 16)
function decodeHex(str) {
    return parseInt(str, 16)
}

var makeCRCTable = function(){
    var c;
    var crcTable = [];
    for(var n =0; n < 256; n++){
        c = n;
        for(var k =0; k < 8; k++){
            c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
        }
        crcTable[n] = c;
    }
    return crcTable;
}

var crc32 = function(str) {
    var crcTable = window.crcTable || (window.crcTable = makeCRCTable());
    var crc = 0 ^ (-1);

    for (var i = 0; i < str.length; i++ ) {
        crc = (crc >>> 8) ^ crcTable[(crc ^ str.charCodeAt(i)) & 0xFF];
    }

    return (crc ^ (-1)) >>> 0;
};

var fakeImageData = function (cont2d, width, height, vector) {
    var imageData = cont2d.getImageData(0, 0, width, height);
    var r = vector.r, g =  vector.g, b = vector.b, a =  vector.a;
    for (var i = 0; i < height; i++) {
        for (var j = 0; j < width; j++) {
            var index = ((i * (width * 4)) + (j * 4));
            imageData.data[index + 0] = imageData.data[index + 0] + r;
            imageData.data[index + 1] = imageData.data[index + 1] + g;
            imageData.data[index + 2] = imageData.data[index + 2] + b;
            imageData.data[index + 3] = imageData.data[index + 3] + a;
        }
    }

    cont2d.putImageData(imageData, 0, 0);

    return cont2d
}

var getCanvas = function(email) {
    var __canvas = document.createElement("canvas");
    var width =  150;
    var height = 60;
    var rearray = [];
    __canvas.width = width;
    __canvas.height = height;
    __canvas.style.display = "inline";
    rearray = [];
    var cont2d = __canvas.getContext("2d");
    cont2d.rect(0, 0,10,10);
    cont2d.rect(2, 2, 6, 6);
    rearray.push(cont2d.isPointInPath(5, 5, "evenodd") === false ? "yes" :"no");
    cont2d.textBaseline = "alphabetic";
    cont2d.fillStyle = "#f60";
    cont2d.fillRect(125, 1, 62, 20);
    cont2d.fillStyle = "#069";
    cont2d.font = "8pt Arial";
    cont2d.fillText("Cwm fjordbank glyphs vext quiz,", 2, 15);
    cont2d.fillStyle = "rgba(102, 204, 0, 0.2)";
    cont2d.font = "11pt Arial";
    cont2d.fillText("Cwm fjordbank glyphs vext quiz,", 4, 45);
    cont2d.globalCompositeOperation = "multiply";
    cont2d.fillStyle = "rgb(255,0,255)";
    cont2d.beginPath();
    cont2d.arc(20, 20, 20, 0, Math.PI * 2, true);
    cont2d.closePath();
    cont2d.fill();
    cont2d.fillStyle = "rgb(0,255,255)";
    cont2d.beginPath();
    cont2d.arc(50, 20, 20, 0, Math.PI * 2, true);
    cont2d.closePath();
    cont2d.fill();
    cont2d.fillStyle = "rgb(255,255,0)";
    cont2d.beginPath();
    cont2d.arc(35,40, 20, 0, Math.PI * 2, true);
    cont2d.closePath();
    cont2d.fill();
    cont2d.fillStyle = "rgb(255,0,255)";
    cont2d.arc(20, 25,10, 0, Math.PI * 2, true);
    cont2d.arc(20, 25, 20, 0, Math.PI * 2, true);
    cont2d.fill("evenodd");
    var gstyle = cont2d.createLinearGradient(40, 50, 60, 78);
    gstyle.addColorStop(0, "blue");
    gstyle.addColorStop(0.5, "red");
    gstyle.addColorStop(1, "white");
    cont2d.fillStyle = gstyle;
    cont2d.beginPath();
    cont2d.arc(70, 50,10, 0, Math.PI * 2, true);
    cont2d.closePath();
    cont2d.fill();
    cont2d.font = "10pt dfgstg";
    cont2d.strokeText(Math.tan(-1e+300).toString(), 4, 30);
    cont2d.fillText(Math.cos(-1e+300).toString(), 4,40);
    cont2d.fillText(Math.sin(-1e+300).toString(), 4, 50);
    cont2d.beginPath();
    cont2d.moveTo(25, 0);
    cont2d.quadraticCurveTo(1, 1, 1, 5);
    cont2d.quadraticCurveTo(1, 76, 26,10);
    cont2d.quadraticCurveTo(26, 96, 6,12);
    cont2d.quadraticCurveTo(60, 96,41,10);
    cont2d.quadraticCurveTo(121, 86, 101, 7);
    cont2d.quadraticCurveTo(121, 1, 56, 1);
    cont2d.stroke();
    cont2d.globalCompositeOperation = "difference";
    cont2d.fillStyle = "rgb(255,0,255)";
    cont2d.beginPath();
    cont2d.arc(80, 20, 20, 0, Math.PI * 2, true);
    cont2d.closePath();
    cont2d.fill();
    cont2d.fillStyle = "rgb(0,255,255)";
    cont2d.beginPath();
    cont2d.arc(110, 20, 20, 0, Math.PI * 2, true);
    cont2d.closePath();
    cont2d.fill();
    cont2d.fillStyle = "rgb(255,255,0)";
    cont2d.beginPath();
    cont2d.arc(95,40, 20, 0, Math.PI * 2, true);
    cont2d.closePath();
    cont2d.fill();
    cont2d.fillStyle = "rgb(255,0,255)";
    rearray.push("canvas fp:" + __canvas.toDataURL());
    var base64_1 = __canvas.toDataURL();

    var crc32Value = crc32(rearray.join("~"));
    var emailHash = null;
    var _IILi =  (email || "Not Available").toUpperCase();
    cont2d.fillStyle = "#808080";
    cont2d.font = "8pt Arial";
    cont2d.fillText(_IILi, 2, 30);
    emailHash = crc32(__canvas.toDataURL());

    var __data = {
        hash: crc32Value,
        emailHash: emailHash,
        histogramBins: histogramBins(cont2d.getImageData(0, 0, width, height).data),
        base64_1: base64_1,
        base64_2:__canvas.toDataURL(),
    };

    return __data
}